package com.excellent.item.service.impl;

import com.excellent.common.PageResult;
import com.excellent.item.bo.SpuBo;
import com.excellent.item.mapper.*;
import com.excellent.item.pojo.*;
import com.excellent.item.service.CategoryService;
import com.excellent.item.service.GoodsService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * @author Xxacker
 */
@Slf4j
@Service("GoodsService")
public class GoodsServiceImpl implements GoodsService {

    @Autowired
    private SpuMapper spuMapper;

    @Autowired
    private SpuDetailMapper spuDetailMapper;

    @Autowired
    private SkuMapper skuMapper;

    @Autowired
    private StockMapper stockMapper;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private BrandMapper brandMapper;

    //使用 rabbitMQ ，首先需要注入 amqp 的模板
    @Autowired
    private AmqpTemplate amqpTemplate;

    /**
     * 1. 添加查询条件
     * 2. 添加上下架过滤条件
     * 3. 添加分页
     * 4. 执行查询
     * 5. spu集合转化为spuBo的集合
     * 6. 返回 PageResult<spuBo>
     */
    @Override
    public PageResult<SpuBo> querySpuBoByPage(String key, Boolean saleable, Integer page, Integer rows) {
        Example example = new Example(Spu.class);
        // 通过 Criteria 来进行添加查询条件
        Example.Criteria criteria = example.createCriteria();
        // 搜索条件
        if (StringUtils.isNotBlank(key)) {
            // 01. 添加针对标题的模糊查询
            criteria.andLike("title", "%" + key + "%");
        }
        if (saleable != null) {
            // 02. 添加上下架的过滤条件
            criteria.andEqualTo("saleable", saleable);
        }

        // 03. 分页条件：page是页数，rows是每页显示的条数
        PageHelper.startPage(page, rows);

        // 04. 执行查询【模糊查询】
        List<Spu> spus = this.spuMapper.selectByExample(example);
        PageInfo<Spu> pageInfo = new PageInfo<>(spus);

        // SPU 集合转换成 spubo 的集合
        List<SpuBo> spuBos = new ArrayList<>();
        spus.forEach(spu->{
            SpuBo spuBo = new SpuBo();
            // copy共同属性的值复制到新的对象
            BeanUtils.copyProperties(spu, spuBo);
            // 查询分类名称
            List<String> names = this.categoryService.queryNamesByIds(Arrays.asList(spu.getCid1(), spu.getCid2(), spu.getCid3()));
            // 进行分割
            spuBo.setCname(StringUtils.join(names, " / "));
            // 查询品牌的名称
            Brand brand = this.brandMapper.selectByPrimaryKey(spu.getBrandId());
            if(brand != null){
                spuBo.setBname(brand.getName());
            }
            spuBos.add(spuBo);
        });
        return new PageResult<>(pageInfo.getTotal(), spuBos);  //pageInfo.getTotal() 表示总条数
    }

    /**
     * 新增商品
     * 1. 先新增   spu
     * 2. 再去新增 spuDetail
     * 3. 新增     sku
     * 4. 新增     stock
     * @param spuBo
     */
    @Transactional
    public void saveGoods(SpuBo spuBo) {
        // 新增spu
        // 设置默认字段
        spuBo.setId(null);
        spuBo.setSaleable(true);
        spuBo.setValid(true);
        spuBo.setCreateTime(new Date());
        spuBo.setLastUpdateTime(spuBo.getCreateTime());
        this.spuMapper.insertSelective(spuBo);

        // 新增spuDetail
        SpuDetail spuDetail = spuBo.getSpuDetail();
        spuDetail.setSpuId(spuBo.getId());
        this.spuDetailMapper.insertSelective(spuDetail);

        saveSkuAndStock(spuBo);
        // 给 rabbitMQ 发送消息,该方法被抽取
        sendMsg("insert", spuBo.getId());
    }

    /**
     * MQ中的增、删、改都会用到该消息
     * @param type
     * @param id
     */
    private void sendMsg(String type, Long id) {
        try {
            // rabbitMQ 发送不成功，不应该触发事务回滚，所以应该使用try{}cache{}
            this.amqpTemplate.convertAndSend("item." + type, id);
        } catch (AmqpException e) {
            System.out.println("type" + type + ", 商品消息发送异常：" + e + "，商品id：" + id);
            e.printStackTrace();
        }
    }

    /**
     * 保存 sku 和 stock
     * @param spuBo
     */
    private void saveSkuAndStock(SpuBo spuBo) {
        spuBo.getSkus().forEach(sku -> {
            // 新增sku
            sku.setSpuId(spuBo.getId());
            sku.setCreateTime(new Date());
            sku.setLastUpdateTime(sku.getCreateTime());
            this.skuMapper.insertSelective(sku);

            // 新增库存
            Stock stock = new Stock();
            stock.setSkuId(sku.getId());
            stock.setStock(sku.getStock());
            this.stockMapper.insertSelective(stock);
        });
    }

    /**
     * 根据spuId查询spuDetail
     * @param spuId
     * @return
     */
    public SpuDetail querySpuDetailBySpuId(Long spuId) {
        return this.spuDetailMapper.selectByPrimaryKey(spuId);
    }

    /**
     * 根据spuId查询sku的集合
     * @param spuId
     * @return
     */
    public List<Sku> querySkusBySpuId(Long spuId) {
        Sku sku = new Sku();
        sku.setSpuId(spuId);
        List<Sku> skus = this.skuMapper.select(sku);
        skus.forEach(skuItem -> {
            Stock stock = this.stockMapper.selectByPrimaryKey(skuItem.getId());
            skuItem.setStock(stock.getStock());
        });
        return skus;
    }

    /**
     * 1. 先删除与 sku 相关的表
     *  1.1 删除 stock 表；
     *  1.2 再删除 sku 表
     *
     * 2. 新增与 sku 相关的表
     *  2.1 新增 sku 表；
     *  2.2 再新增 stock 表
     *
     * 3. 更新 spu 和 spuDetail 表
     * */
    @Transactional
    public void updateGoods(SpuBo spuBo) {
        // 查询以前sku
        Sku oldSku = new Sku();
            oldSku.setSpuId(spuBo.getId());
        List<Sku> skus = this.skuMapper.select(oldSku);

        // 如果以前存在，则删除
        if(!CollectionUtils.isEmpty(skus)) {
            // 删除以前库存
            skus.forEach(sku ->{
                    this.stockMapper.deleteByPrimaryKey(sku.getId());
            });
            // 删除以前的sku
            this.skuMapper.delete(oldSku);
        }

        // 新增sku和库存
        this.saveSkuAndStock(spuBo);

        // 更新spu
        spuBo.setLastUpdateTime(new Date());  //根据系统当前时间设置最后更改时间
        spuBo.setCreateTime(null);            //创建时间不能随便更新，防止他人恶更新创建时间
        spuBo.setValid(null);                 //是否有效
        spuBo.setSaleable(null);              //是否上架
        this.spuMapper.updateByPrimaryKeySelective(spuBo);

        // 更新spu详情
        this.spuDetailMapper.updateByPrimaryKeySelective(spuBo.getSpuDetail());

        // 给 rabbitMQ 发送消息
        sendMsg("update", spuBo.getId());
    }

    /**
     * 【删除商品，删除商品后，将商品置为下架】
     * @param spuBo
     */
    @Override
    public void deleteGood(SpuBo spuBo) {
        this.spuMapper.upDateBySpuId(spuBo.getId(), false, !spuBo.getValid());
        // 给 rabbitMQ 发送消息
        sendMsg("delete", spuBo.getId());
    }

    /**
     * 【上/下架商品】
     * @param spuBo
     */
    @Override
    public void editGoodSaleable(SpuBo spuBo) {
        this.spuMapper.upDateBySpuId(spuBo.getId(), !spuBo.getSaleable(), true);
        // 给 rabbitMQ 发送消息
        sendMsg("update", spuBo.getId());
    }

    public Spu querySpuById(Long id) {
        return this.spuMapper.selectByPrimaryKey(id);
    }

    public Sku querySkuById(Long id) { return this.skuMapper.selectByPrimaryKey(id); }

}
